package com.ftwj.demo.global.shiro;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
//import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
//import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ftwj.demo.permission.dao.ResourceDao;
import com.ftwj.demo.permission.dao.RoleDao;
import com.ftwj.demo.permission.dao.UserDao;
import com.ftwj.demo.permission.entity.ResourceBean;
import com.ftwj.demo.permission.entity.RoleBean;
import com.ftwj.demo.permission.entity.UserBean;


@Component
public class CustomShiroRealm extends AuthorizingRealm {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(CustomShiroRealm.class);
    
	/**
	 * 	此处由于Shiro的CustomShiroRealm提交加载导致类中的 @Cache @Transactional 注解失效
	 * @Lazy 注解让注入Bean延迟加载可解决此问题
	 */
    @Autowired
    @Lazy
    private UserDao userDao;
    @Autowired
    @Lazy
    private RoleDao roleDao;;
    @Autowired
    @Lazy
    private ResourceDao resourceDao;
    @Autowired
    @Lazy
    private SessionDAO sessionDAO;

	//加密方式，后期需要修改进CustomShiroConfig中
    /*
	{
        HashedCredentialsMatcher hashMatcher = new HashedCredentialsMatcher();
        hashMatcher.setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
        hashMatcher.setStoredCredentialsHexEncoded(true);
        hashMatcher.setHashIterations(64);
        this.setCredentialsMatcher(hashMatcher);
    }
    */

    @Override
    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection方法参数不能为空");
        }
    	
    	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    	ShiroPrincipal shiroPrincipal= (ShiroPrincipal) principals.getPrimaryPrincipal();

    	/**
    	List<String> roles=new ArrayList<String>();
    	List<String> resources=new ArrayList<String>();
        Integer userId=shiroPrincipal.getUserId();
        List<RoleBean> roleList = roleDao.selectListByUserId(userId);
        List<ResourceBean> resourceList = new ArrayList<ResourceBean>();
        for (RoleBean role : roleList) {
			Integer roleId = role.getRoleId();
			List<ResourceBean> resource = resourceDao.selectListByRoleId(roleId);
			resourceList.addAll(resource);
		}

    	for (RoleBean role : roleList) {
			String roleName = role.getRoleTitle();
			roles.add(roleName);
		}
    	for (ResourceBean resource : resourceList) {
    		String resourceTitle=resource.getPermission();
    		resources.add(resourceTitle);
		}
    	//把List<RoleBean>放入ShiroPrincipal
    	shiroPrincipal.setRoles(roles);
    	//把List<Permission>放入ShiroPrincipal
    	shiroPrincipal.setPermissions(resources);
    	*/
    	// 添加角色和权限
    	info.addRoles(shiroPrincipal.getRoles());
        info.addStringPermissions(shiroPrincipal.getPermissions());
        LOGGER.info("用户角色："+info.getRoles());
        LOGGER.info("角色权限："+info.getStringPermissions());
        return info;
    }

    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	ShiroPrincipal shiroPrincipal=new ShiroPrincipal();
    	Collection<Session> sessions = sessionDAO.getActiveSessions();
    	sessions.stream().map(session -> session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)).collect(Collectors.toList());;

        UsernamePasswordToken upt=(UsernamePasswordToken) token;
        String phone=upt.getUsername();
		Wrapper<UserBean> queryUserWrapper=new QueryWrapper<UserBean>().eq("phone", phone).or().eq("login_name", phone);
		UserBean bean = userDao.selectOne(queryUserWrapper);
        if(ObjectUtils.isEmpty(bean)){
            throw new UnknownAccountException();
        } 
        if(bean.getState()!=1){
            throw new DisabledAccountException();
        }
        Integer userId=bean.getUserId();
        String hashedCredentials=bean.getPassword();
        String salt=bean.getSalt();
        //把User信息放入ShiroPrincipal
        shiroPrincipal.setUserId(userId);
        shiroPrincipal.setShowName(bean.getShowName());
        shiroPrincipal.setLoginName(bean.getLoginName());
        shiroPrincipal.setPhone(phone);
        //设置用户角色和权限
        //setRoleAndPermission(shiroPrincipal);
        ByteSource credentialsSalt=ByteSource.Util.bytes(salt);
        String realmName=getName();
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(shiroPrincipal, hashedCredentials, credentialsSalt, realmName);
        return info;
    }
    
    /**
     * 
     * <p>Title: setPermission</p>  
     * <p>Description: 异步设置登录用户的</p>  
     * @param shiroPrincipal 
     * @author WangSLi
     * @date 2020年5月29日  
     * @version 1.0
     */
    private void setRoleAndPermission(ShiroPrincipal shiroPrincipal) {
    	Integer userId = shiroPrincipal.getUserId();
        List<String> roles=new ArrayList<String>();
        List<String> resources=new ArrayList<String>();
        List<RoleBean> roleList = roleDao.selectListByUserId(userId);
        List<ResourceBean> resourceList = new ArrayList<ResourceBean>();
        for (RoleBean role : roleList) {
			Integer roleId = role.getRoleId();
			List<ResourceBean> resource = resourceDao.selectListByRoleId(roleId);
			resourceList.addAll(resource);
		}
    	for (RoleBean role : roleList) {
			String roleName = role.getRoleTitle();
			roles.add(roleName);
		}
    	for (ResourceBean resource : resourceList) {
    		String resourceTitle=resource.getPermission();
    		resources.add(resourceTitle);
		}
    	//把List<RoleBean>放入ShiroPrincipal
    	shiroPrincipal.setRoles(roles);
    	//把List<Permission>放入ShiroPrincipal
    	shiroPrincipal.setPermissions(resources);
    }

    
    public static void main(String[] args) {
        String salt=UUID.randomUUID().toString().replace("-", "");
        System.out.println("盐值："+salt);
        ByteSource credentialsSalt=ByteSource.Util.bytes(salt);
        String algorithmName="MD5";
        String source = "12345678";
        SimpleHash passowrd = new SimpleHash(algorithmName, source, credentialsSalt, 64);
        System.out.println("密码："+passowrd);
    }
}
